package com.fly.uaa.exceptionhandler;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fly.common.common.ErrorConstant;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CustomOauth2ExceptionDeserializer extends StdDeserializer<CustomOauth2Exception> {

    public CustomOauth2ExceptionDeserializer() {
        super(CustomOauth2Exception.class);
    }

    @Override
    public CustomOauth2Exception deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        JsonToken t = jsonParser.getCurrentToken();
        if (t == JsonToken.START_OBJECT) {
            t = jsonParser.nextToken();
        }
        Map<String, Object> errorParams = new HashMap<String, Object>();
        for (; t == JsonToken.FIELD_NAME; t = jsonParser.nextToken()) {
            // Must point to field name
            String fieldName = jsonParser.getCurrentName();
            // And then the value...
            t = jsonParser.nextToken();
            // Note: must handle null explicitly here; value deserializers won't
            Object value;
            if (t == JsonToken.VALUE_NULL) {
                value = null;
            }
            // Some servers might send back complex content
            else if (t == JsonToken.START_ARRAY) {
                value = jsonParser.readValueAs(List.class);
            } else if (t == JsonToken.START_OBJECT) {
                value = jsonParser.readValueAs(Map.class);
            } else {
                value = jsonParser.getText();
            }
            errorParams.put(fieldName, value);
        }

        Object errorCode = errorParams.get("resultCode");
        String errorMessage = errorParams.containsKey("resultMessages") ? errorParams.get("resultMessages")
                .toString() : null;
        if (errorMessage == null) {
            errorMessage = errorCode == null ? "OAuth Error" : errorCode.toString();
        }

        CustomOauth2Exception exception = getCustomOauth2Exception(Integer.valueOf(errorCode.toString()), errorMessage);
        return exception;
    }

    private CustomOauth2Exception getCustomOauth2Exception(int errorCode, String errorMessage) {
        String OAuth2ErrorCode = "invalid_request";

        switch (errorCode) {
            case ErrorConstant.INVALID_CLIENT:
                OAuth2ErrorCode = "invalid_client";
                break;
            case ErrorConstant.INVALID_GRANT:
                OAuth2ErrorCode = "invalid_grant";
                break;
            case ErrorConstant.INVALID_REQUEST:
                OAuth2ErrorCode = "invalid_request";
                break;
            case ErrorConstant.INVALID_SCOPE:
                OAuth2ErrorCode = "invalid_scope";
                break;
            case ErrorConstant.INVALID_TOKEN:
                OAuth2ErrorCode = "invalid_token";
                break;
            case ErrorConstant.UNAUTHORIZED_USER:
                OAuth2ErrorCode = "unauthorized_user";
                break;
            case ErrorConstant.UNSUPPORTED_GRANT_TYPE:
                OAuth2ErrorCode = "unsupported_grant_type";
                break;
            case ErrorConstant.UNSUPPORTED_RESPONSE_TYPE:
                OAuth2ErrorCode = "unsupported_response_type";
                break;
            case ErrorConstant.ACCESS_DENIED:
                OAuth2ErrorCode = "access_denied";
                break;
            case ErrorConstant.METHOD_EXCEPTION:
                OAuth2ErrorCode = "server_error";
                break;
            case ErrorConstant.UNAUTHORIZED:
                OAuth2ErrorCode = "unauthorized";
                break;
            case ErrorConstant.METHOD_NOT_ALLOWED:
                OAuth2ErrorCode = "method_not_allowed";
                break;
            case ErrorConstant.UNAUTHORIZED_CLIENT:
                OAuth2ErrorCode = "unauthorized_client";
                break;
            case ErrorConstant.INVALID_SIGN:
                OAuth2ErrorCode = "invalid_sign";
                break;
            case ErrorConstant.EMPTY_CLIENT:
                OAuth2ErrorCode = "empty_client";
                break;
            case ErrorConstant.EMPTY_SIGN:
                OAuth2ErrorCode = "empty_sign";
                break;
            default:
                OAuth2ErrorCode = "invalid_request";
        }

        return new CustomOauth2Exception(OAuth2ErrorCode, errorMessage);
    }
}
